package com.bjb.vr.common.utils;


import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.bjb.vr.common.constant.TokenConstants;
import com.bjb.vr.common.exception.CommonException;
import com.bjb.vr.common.result.BaseErrorCode;
import com.bjb.vr.common.result.CommonResult;
import io.jsonwebtoken.*;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 网关过滤器配置
 * @author: HuJingBo
 * @time: 2022/3/3 14:42
 */
public class JwtTokenUtil {

    private static final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;

    /**
     * 签发JWT
     *
     * @param userName  用户名
     * @param loginType
     * @return String
     */
    public static String createJWT(String userName, String tenantId, String loginType) {
        // 自定义参数
        Map<String, Object> claimsMap = new HashMap<String, Object>();
        claimsMap.put(TokenConstants.TOKEN_USERNAME, userName);
        claimsMap.put(TokenConstants.TENANT_ID, tenantId);
        claimsMap.put(TokenConstants.LOGIN_TYPE, loginType);
        String uuid = UUID.fastUUID().toString(true);
        JwtBuilder builder = Jwts.builder().setId(uuid).setSubject(userName)
                .setIssuer(TokenConstants.ISSUER)
                .setIssuedAt(DateTimeUtil.getNowTime())
                .signWith(signatureAlgorithm, generalKey())
                .setClaims(claimsMap)
                .setExpiration(DateTimeUtil.getNextMinute(TokenConstants.EXPIRATION));
        return builder.compact();
    }

    /**
     * 签发设备JWT
     *
     * @param udid 设备唯一标识
     * @return String
     */
    public static String createDevJWT(String udid, String tenantId) {
        // 自定义参数
        Map<String, Object> claimsMap = new HashMap<String, Object>();
        claimsMap.put(TokenConstants.TOKEN_UDID, udid);
        claimsMap.put(TokenConstants.TENANT_ID, tenantId);
        JwtBuilder builder = Jwts.builder().setId(udid).setSubject(udid)
                .setIssuer(TokenConstants.ISSUER)
                .setIssuedAt(DateTimeUtil.getNowTime())
                .signWith(signatureAlgorithm, generalKey())
                .setClaims(claimsMap)
                .setExpiration(DateTimeUtil.getNextMinute(TokenConstants.EXPIRATION));
        return builder.compact();
    }

    /**
     * 验证JWT
     *
     * @param jwtString
     * @return
     */
    public static CommonResult validateJWT(String jwtString) {
        if (StringUtils.isBlank(jwtString)) {
            CommonResult.Fail(BaseErrorCode.UNAUTHORIZED).setMessage(TokenConstants.EMPTY_TOKEN_ERROR);
        }
        Claims claims = null;
        try {
            claims = parseJWT(jwtString);
            return CommonResult.Ok().setResult(claims);
        } catch (ExpiredJwtException e) {
            return CommonResult.Fail(BaseErrorCode.UNAUTHORIZED.getCode(), TokenConstants.EXPIRE_TOKEN_ERROR);
        } catch (SignatureException e) {
            return CommonResult.Fail(BaseErrorCode.UNAUTHORIZED.getCode(), TokenConstants.VALIDATE_TOKEN_SIGNATURE_ERROR);
        } catch (Exception e) {
            return CommonResult.Fail(BaseErrorCode.UNAUTHORIZED.getCode(), TokenConstants.VALIDATE_TOKEN_ERROR);
        }
    }

    /**
     * 生成密钥
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(TokenConstants.SECRET);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 解析JWT字符串
     *
     * @param jwtString
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwtString) {
        Claims claims = null;
        try {
            claims = Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(jwtString).getBody();
        } catch (ExpiredJwtException e) {
            throw new CommonException(TokenConstants.EXPIRE_TOKEN_ERROR);
        } catch (SignatureException e) {
            throw new CommonException(TokenConstants.VALIDATE_TOKEN_SIGNATURE_ERROR);
        } catch (Exception e) {
            throw new CommonException(TokenConstants.VALIDATE_TOKEN_ERROR);
        }
        return claims;
    }
}
